package com.shadow.shiro;

import java.util.*;
import java.util.stream.Collectors;

import com.shadow.common.bo.LoginUser;
import com.shadow.common.entity.Permission;
import com.shadow.common.entity.Role;
import com.shadow.common.entity.User;
import com.shadow.service.PermissionService;
import com.shadow.service.RoleService;
import com.shadow.service.UserService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.BeanUtils;

import javax.annotation.Resource;

/**
 * 自定义 ShiroDbRealm 实现 Shiro Realm 的登录和认证.
 * @author Pbody
 * @create: 2019-04-01 16:33
 */
public class ShiroDbRealm extends AuthorizingRealm {

    @Resource
    private UserService userService;
    @Resource
    private RoleService roleService;
    @Resource
    private PermissionService permissionService;

    /**
     * 认证.
     * SecurityUtils.getSubject().login(token)
     *
     * */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(final AuthenticationToken authenticationToken) throws AuthenticationException {
        LoginUser loginUser = new LoginUser();
        String account = (String) authenticationToken.getPrincipal();
        if (null != account) {
            User user = userService.getUserByAccount(account);
            if (null != user) {
                Set<String> roles = new HashSet<>();       //角色set
                Set<Permission> permissionSet = new HashSet<>(); //权限set
                BeanUtils.copyProperties(user, loginUser);
                // --------------------  user -> role list  -------------------- //
                List<Role> roleList = roleService.getRoleListByUserId(user.getId());
                // --------------------  role -> menu list  -------------------- //
                Optional.ofNullable(roleList)
                        .filter(CollectionUtils::isNotEmpty)
                        .ifPresent(list -> list.forEach(role -> {
                            roles.add(role.getCode());     //添加角色
                            Optional.ofNullable(permissionService.getPermissionListByRoleId(role.getId()))
                                    .filter(CollectionUtils::isNotEmpty)
                                    .ifPresent(permissionSet::addAll);
                        }));
                loginUser.setRoles(roles);
                loginUser.setPermissions(
                        permissionSet.stream()
                                .sorted(Comparator.comparing(Permission::getOrderNum))
                                .map(Permission::getCode)
                                .collect(Collectors.toSet())
                );
                return new SimpleAuthenticationInfo(loginUser, loginUser.getPassword(), getName());
            }
        }
        return null;
    }

    /**
     * 授权.
     * 授权 ==> 执行isPermitted()或注解( @RequiresPermissions()/@RequiresRoles() )进入
     *
     * @return {@link AuthorizationInfo}
     * */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(final PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        Optional.ofNullable(loginUser).ifPresent(x -> {
            info.setRoles(loginUser.getRoles());
            info.addStringPermissions(loginUser.getPermissions());
        });
        return info;
    }
}
